(function(win){
    function module(){
        this.context = {
            baseUrl: './',
            alias: {},
            entry: 'main.js',
            suffix: '.js',
        }
        this.deps = {};
        this.srcs = [];
        this.customEvt = new module.CustomEvt();
        this.ready();
    }
    
    var utils = module.utils = {
        each(arr, callback){
            var keys = Object.keys(arr);
            for(var i = 0; i < keys.length; i++) { 
                if(callback.call(arr, arr[i], i) === false) {
                    break;
                }
            }
        },
        // 只保留指定的keys
        inKeys(target, keys) {
            return Object.keys(target).reduce((newData, key) => {
                if (keys.includes(key)) {
                    newData[key] = target[key];
                }
                return newData;
            }, {});
        },
        // 路径拼接
        pathJoin(...paths){
            let path = '';
            for(let i = paths.length - 1; i > -1; i--) {
                let pathItem = paths[i].replace(/\/+$/, '');
                // 如果是绝对路径
                if(/^\//.test(pathItem)) {
                    path = pathItem + '/'+ path;
                    break;
                }
                // 如果是相对路径
                if(/^\.\//.test(pathItem)) {
                    pathItem = pathItem.slice(2)
                }
                // 如果是: ../../a/b/c
                if(/^(\.{2}\/)+\S+/.test(pathItem) && paths[i-1]) {
                    let matches = null;
                    while(matches = /^\.{2}\/(\S+)/.exec(pathItem)) {
                        pathItem = matches[1];
                        let prevPath = paths[i-1].replace(/\/+$/, '');
                        if(prevPath) {
                            paths[i-1] = prevPath.slice(0, prevPath.lastIndexOf('/'))
                        }
                    }
                }
                path = pathItem + '/'+ path;
            }
            return path.replace(/\/+$/, '');
        },
        createScript(src) {
            var node = document.createElement('script');
            node.type = 'text/javascript';
            node.async = true;
            node.src = src;
            return node;
        },
        // 判断所有依赖是否加载完成
        isDepsDone(options) {
            var { depsTree, entry = depsTree.entry, deps } = options;
            var deps = deps || depsTree[entry].deps;
            var done = true;
            utils.each(deps, function(moduleName) {
                var dep = depsTree[moduleName];
                if(dep) {
                    if(dep.deps.length > 0) {
                        done = utils.isDepsDone({
                            depsTree,
                            entry,
                            deps: dep.deps
                        });
                        if(!done) {
                            return false;
                        }
                    }
                }else {
                    done = false;
                    return false;
                }
            });
            return done;
        }
    }

    var CustomEvt = function(){
        this.subEvents = {};
    };

    CustomEvt.prototype = {
        constructor:CustomEvt
        ,$emit:function(event,data){
            event = this.subEvents[event];
            if(event){
                for(let i = 0; i < event.length; i++){
                    event[i].apply(this, data);
                }
            }
            return this;
        }
        ,$on:function(event,handle){
            let subEvents = this.subEvents;
            !(event in subEvents) && (subEvents[event] = [])
            subEvents[event].push(handle);
            return this;
        }
        ,$off:function(event,handle){
            let events = this.subEvents[event];
            if(!handle){
                events && Reflect.deleteProperty(this.subEvents, event);
            }else{
                if(typeof handle == 'function' && events){
                    for(let i = 0,len = events.length; i < len; i++){
                        let event = events[i];
                        if(event == handle){
                            return events.splice(i,1);
                        }
                    } 
                }
            }
            return this;
        }
    }

    module.CustomEvt = CustomEvt;

    // // 主题对象
    // function Subject() {
    //     this.observers = [];
    // }
    // // 添加观察者
    // Subject.prototype.addObserver = function(observer) {
    //    !this.observers.includes(observer) && this.addObserver.push(observer);
    // }
    // Subject.prototype.notify = function(message) {
    //     this.observers.forEach(observer => {
    //         observer.update(message);//观察者接收消息的方法
    //     })
    // }
    // function Observer() {}
    // Observer.prototype.update = function(message) {
    // }

    Object.assign( module.prototype, {
        // 入口函数
        ready() {
            this.setCtxProxy();
            // 这里默认加载同级目录下的main.js，请确保main.js的存在
            var script = utils.createScript(this.getUrl('./', this.entry));
            document.body.appendChild(script);
        },
        // 设置context对象的属性，通过代理访问
        setCtxProxy(){
            var _self = this;
            var ctx = this.context;
            utils.each(Object.keys(ctx), function(key) {
                Object.defineProperty(_self, key, {
                    get: function() {
                        return ctx[key];
                    },
                    set: function(value) {
                        if(ctx[key] !== value) {
                            ctx[key] = value;
                            return true;
                        }
                    }
                })
            });
        },
        configs(options) {
            Object.assign(this.context, utils.inKeys(options, ['baseUrl', 'alias', 'entry']))
            return this;
        },
        getUrl(baseUrl, moduleName) {
            var path = utils.pathJoin(baseUrl, moduleName);
            return new RegExp('\\'+this.suffix+'$').test(path) ? path : path + this.suffix;
        },
        // 核心方法：define，收集依赖
        define(moduleName, deps, factory) {
            typeof deps == 'function' && (
                factory = deps,
                deps = []
            )
            if(!this.deps[moduleName]) {
                this.deps[moduleName] = {
                    moduleName,
                    deps,
                    factory
                };
            }
        },
        // 核心方法
        // 迭代收集每一个入口依赖
        traverseDeps(deps, callback){
            var _self = this;

            function buildDepsRelation(moduleName, depsTree) {
                var oldDepsTree = depsTree;
                var module = _self.deps[moduleName];
                depsTree = depsTree || { entry: moduleName };
                depsTree[moduleName] = module;
                if(module.deps.length > 0) {
                    traverseScript(module.deps, depsTree);
                }else {
                    // 所有依赖收集完，才返回
                    if(utils.isDepsDone({ depsTree })) {
                        typeof callback == 'function' && callback(depsTree);
                    }
                }
                // 表示是第一层的递归，只重置第一层的递归
                if(!oldDepsTree) {
                    depsTree = null;
                }
            }

            function traverseScript(deps, depsTree) {
                utils.each(deps, function(moduleName, i) {
                    var curSrc = _self.getUrl(_self.baseUrl, moduleName);
                    var isExistSrc = _self.srcs.includes(curSrc);
                    // 判断相同的依赖是否已经加载过
                    if(!isExistSrc) {
                        _self.srcs.push(curSrc);
                        var script = utils.createScript(curSrc);
                        script.onload = function() {
                            _self.customEvt.$emit('scriptLoaded', [moduleName])
                            buildDepsRelation(moduleName, depsTree);
                        }
                        document.body.appendChild(script);
                    }else {
                        let curModuleName = moduleName;
                        // 1，依赖已加载完成
                        if(_self.deps[curModuleName]) {
                            buildDepsRelation(moduleName, depsTree);
                        }else {
                            // 2，scriptLoad加载完成后，this.deps才有值
                            _self.customEvt.$on('scriptLoaded', function(moduleName) {
                                if(moduleName == curModuleName) {
                                    buildDepsRelation(moduleName, depsTree);
                                }
                            });
                        }
                    }
                })
            }

            traverseScript(deps)
        },
        // 一次收集全部依赖树的依赖
        getAllDeps(initDeps, callback) {
            var _self = this;
            function traverseDeps(deps) {
                utils.each(deps, function(moduleName) {
                    var curSrc = _self.getUrl(_self.baseUrl, moduleName);
                    var isExistSrc = _self.srcs.includes(curSrc);
                    // 判断相同的依赖是否已经加载过
                    if(!isExistSrc) {
                        _self.srcs.push(curSrc);
                        var script = utils.createScript(curSrc);
                        script.onload = function() {
                            var module = _self.deps[moduleName];
                            if(module.deps.length > 0) {
                                traverseDeps(module.deps);
                            }else {
                                // 所有依赖收集完，才返回
                                var isDone = initDeps
                                .map(entryDep => utils.isDepsDone({ depsTree: _self.deps, entry: entryDep }))
                                .every(isDone => isDone === true);
                                if(isDone){
                                    typeof callback == 'function' && callback(_self.deps);
                                }
                            }
                        }
                        document.body.appendChild(script);
                    }else {
                        // 所有依赖收集完，才返回
                        var isDone = initDeps
                        .map(entryDep => utils.isDepsDone({ depsTree: _self.deps, entry: entryDep }))
                        .every(isDone => isDone === true);
                        if(isDone){
                            typeof callback == 'function' && callback(_self.deps);
                        }
                    }
                })
            }
            traverseDeps(initDeps)
        },
        require(deps, factory) {
            typeof deps == 'string' && (deps = [deps]);
            // 迭代收集每一个入口依赖
            this.traverseDeps(deps, function(depsTree) {
                console.log(depsTree);
            });
    
            // 一次性收集所有依赖
            // this.getAllDeps(deps, function(alldeps) {
            //     console.log(alldeps)
            // })
        }
    });
    win.module = new module();
})(this);